﻿using FreeRobot.View;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;

namespace FreeRobot.Common
{
    unsafe class RobotHelper : IDisposable
    {
        readonly CSharpCode _code;
        private MapEx _mapEx;
        readonly object _lock = new object();
        public RobotHelper()
        {
            _code = new CSharpCode("Out.exe");
            _code.ErrorCallback += _code_ErrorCallback;
            _code.SuccessCallback += _code_SuccessCallback;
        }
        public event Action CompletedCallback;
        void _code_SuccessCallback(string obj)
        {
            lock (_lock)
            {
                var result = obj.Split(',').Select(t => t.Trim()).Where(t => !string.IsNullOrWhiteSpace(t)).ToArray();

                Trace.WriteLine(string.Join("&", result));
                fixed (String* ptr = result)
                {
                    for (int i = 0; i < result.Length; i++)
                    {
                        var curPtr = ptr + i;
                        System.Drawing.Point curPoint = System.Drawing.Point.Empty;
                        float angle = _map.Angle;
                        if (*curPtr == OperateEnum.__FreeRobot__Move.ToString())
                        {
                            if (_map.Angle == 0f)
                                curPoint = new System.Drawing.Point(_map.RobotPoint.X + 1, _map.RobotPoint.Y);
                            else if (_map.Angle == -90f)
                                curPoint = new System.Drawing.Point(_map.RobotPoint.X, _map.RobotPoint.Y - 1);
                            else if (_map.Angle == -180f)
                                curPoint = new System.Drawing.Point(_map.RobotPoint.X - 1, _map.RobotPoint.Y);
                            else if (_map.Angle == -270f)
                                curPoint = new System.Drawing.Point(_map.RobotPoint.X, _map.RobotPoint.Y + 1);
                            _map.RobotPoint = curPoint;
                        }
                        else if (*curPtr == OperateEnum.__FreeRobot__TurnLeft.ToString())
                        {
                            _map.Angle -= 90f;
                        }

                        if (_map.RobotPoint == curPoint || _map.Angle != angle)
                            Thread.Sleep(150);
                    }
                    if (_map.Completed)
                    {
                        if (CompletedCallback != null)
                        {
                            _code.Kill();
                            CompletedCallback();
                        }
                    }
                }
            }
        }

        void _code_ErrorCallback(System.CodeDom.Compiler.CompilerResults arg1, System.CodeDom.Compiler.CompilerErrorCollection arg2)
        {

        }
        public void Reset()
        {
            lock (_lock)
            {
                _map.RobotPoint = new Point(0, 0);
                _map.Angle = 0f;
            }
        }
        private RobotMap _map;
        public void SetMap(RobotMap map)
        {
            _map = map;
            _mapEx = new MapEx(_map.MapRow, _map.MapColumn);
        }
        public void SetMap(int index)
        {
            var info= _mapEx.GetMap(index);
            _map.LoadMap(info);
        }
        public void Excute(string code)
        {
            if (string.IsNullOrWhiteSpace(code)) return;

            string newCode = code.Substring(0, code.LastIndexOf('}'));
            newCode = newCode.Substring(0, newCode.LastIndexOf('}'));
            newCode += Move();
            newCode += TurnLeft();
            newCode += "}}";
            _code.Excute(newCode);
        }
        private string Move()
        {
            return WriteLine(OperateEnum.__FreeRobot__Move, "Move");
        }
        private string TurnLeft()
        {
            return WriteLine(OperateEnum.__FreeRobot__TurnLeft, "TurnLeft");
        }
        private string WriteLine(OperateEnum type, string name)
        {
            string temp = type.ToString() + ",";
            return @" 
            public static void " + name + "()" + "{Console.WriteLine(\"" + temp + "\");}";

        }
        public void Dispose()
        {
            _code.Dispose();
        }
    }
}
